/*
 *  Population.cpp
 *  Genetski
 *
 *  Created by Srđan Rašić on 11/19/11.
 *
 */
#include "Population.h"
#include <cstdlib>
#include <cmath>
#include <vector>
#include <limits>
#include <iostream>
#include "Helper.h"

Population::Population(Function& f, unsigned int numberOfIndividuals, bool minimization, int precision) :
_minimization(minimization), _function(f) {
	double dg = f.Domain().first;
	double gg = f.Domain().second;
	
	_chromosomeSize = ceil(log2((gg-dg)*pow(10, precision) + 1));
	
	resize(numberOfIndividuals, Chromosome(0,0));
	
	_maxFuncValue = std::numeric_limits<double>::min();
	_minFuncValue = std::numeric_limits<double>::max();

	for (int i = 0; i < numberOfIndividuals; i++) {
		Chromosome ch(f.Dimensions(), _chromosomeSize);
		
		while (exists(ch))
			ch = Chromosome(f.Dimensions(), _chromosomeSize);
		
		(*this)[i] = ch;
		
		std::vector<double> x = (*this)[i].Values();
		
		for (int j = 0; j < x.size(); j++)
			x[j] = dg + x[j]/(double)(pow(2, _chromosomeSize)-1)*(gg-dg);
		
		double value = _function(x);
		
		if (value > _maxFuncValue)
			_maxFuncValue = value;
		if (value < _minFuncValue)
			_minFuncValue = value;
	}
	
	_bestChromosomeIndex = 0;
	
	for (int i = 1; i < size(); i++)
		if (Fitness(i) > _bestChromosomeIndex)
			_bestChromosomeIndex = i;
	
	std::cout << "Population of " << size() << " chromosomes generated." << std::endl;
	std::cout << "Best individulal in initial population is: f(" << printVector(ChromosomeValue(_bestChromosomeIndex))
					<< ") = " << _function(ChromosomeValue(_bestChromosomeIndex)) << std::endl;
}

int& Population::BestIndividualIndex() {
	return _bestChromosomeIndex;
}

std::vector<double> Population::ChromosomeValue(unsigned int index) {
	std::vector<double> x = (*this)[index].Values();
	
	double dg = _function.Domain().first;
	double gg = _function.Domain().second;
	
	int partLength = (*this)[0].PartLength();
	
	for (int j = 0; j < x.size(); j++)
		x[j] = dg + x[j]/(double)(pow(2.0, partLength)-1)*(gg-dg);
	
	return x;
}

double Population::Fitness(unsigned int index) {	
	std::vector<double> x = ChromosomeValue(index);
	
	double value = _function(x);
	
	if (_minimization)
		return _maxFuncValue - value;
	else
		return value - _minFuncValue;
}

bool Population::exists(Chromosome& ch) {
	for (int i = 0; i < size(); i++)
		if ((*this)[i] == ch)
			return true;
	return false;
}